﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace fes
{
  class RSI: Indicator, IIndicator
  {
    private int n = 0;
    private List<double> prices;
    private double currentValue = -1;
    private double avgUYesterday = -1;
    private double avgDYesterday = -1;
    
    public RSI(Dictionary<String, Object> parameters) : base("RSI")
    {
      base.setInidicatorParams(parameters);
      n = (int) parameters["n"] + 1;
      prices = new List<double>();
    }
    public void setParameters(Dictionary<String, Object> parameters)
    {

        base.setInidicatorParams(parameters);
        n = (int)parameters["n"] + 1;
    }

    public override Indicator Clone()
    {
      Indicator r = new RSI(base.P);
      r.P = new Dictionary<string, object>();
      foreach (KeyValuePair<String, object> kvp in base.P)
        r.P.Add(kvp.Key, kvp.Value);
      foreach (FuzzySet fs in fuzzySets)
      {
        r.fuzzySets.Add(new FuzzySet(fs.Hedge, fs.name, fs.T));
      }
      return r;
    }

    public override void pushNextDayData(double open, double high, double low, double close, int vol)
    {
      prices.Add(close);
      if (prices.Count > n)
      {
        prices.RemoveAt(0);
      }
      calculateRSI();
    }

    public override double getValue()
    {
      return currentValue;
    }

    private void calculateRSI()
    {
      if (prices.Count == n)  //http://en.wikipedia.org/wiki/Relative_strength_index
      {
        if (avgDYesterday == -1)  //count initial averages
        {
          List<double> positive = new List<double>();
          List<double> negative = new List<double>();
          double sum = 0;
          for (int i = 0; i < n - 1; i++)
          {
            if (prices[i] < prices[i + 1])
            {
              positive.Add(prices[i + 1] - prices[i]);
            }
            else if (prices[i] > prices[i + 1])
            {
              negative.Add(prices[i] - prices[i + 1]);
            }
            else
            {
              positive.Add(0);
              negative.Add(0);
            }
          }
          for (int i = 0; i < positive.Count; i++)
          {
            sum += positive[i];
          }
          if (positive.Count == 0)
          {
            avgUYesterday = 0;
          }
          else
          {
            avgUYesterday = sum / positive.Count;
          }

          sum = 0;
          for (int i = 0; i < negative.Count; i++)
          {
            sum += negative[i];
          }
          if (negative.Count == 0)
          {
            avgDYesterday = 0;
          }
          else
          {
            avgDYesterday = sum / negative.Count;
          }

        }

        int cnt = prices.Count;
        if (prices[cnt - 2] < prices[cnt - 1])
        {
          avgUYesterday = (avgUYesterday * (n - 2) + prices[cnt - 1] - prices[cnt - 2]) / (n - 1);
          avgDYesterday = (avgDYesterday * (n - 2)) / (n - 1);
        }
        else if (prices[cnt - 2] > prices[cnt - 1])
        {
          avgUYesterday = (avgUYesterday * (n - 2)) / (n - 1);
          avgDYesterday = (avgDYesterday * (n - 2) + prices[cnt - 2] - prices[cnt - 1]) / (n - 1);
        }
        else
        {
          avgUYesterday = (avgUYesterday * (n - 2)) / (n - 1);
          avgDYesterday = (avgDYesterday * (n - 2)) / (n - 1);
        }

        currentValue = 100 - (100 / (1 + avgUYesterday / avgDYesterday));
      }
      else
      {
        currentValue = -1;
      }
    }
  }
}
